﻿using System;
using System.Linq;
using System.Collections;
using System.Data.Entity;
using System.Linq.Expressions;
using System.Collections.Generic;
using Optum.SN.Infra.Core.Dependency.Service;

namespace Optum.SN.Infra.Core.TestBase
{
    /// <summary>
    /// Allows mock data to act as though returned from database.
    /// </summary>
    /// <typeparam name="T">Mock data entity type.</typeparam>
    public abstract class MockData<T> : DbSet<T>, IQueryable<T>, IEntity where T : class
    {
        /// <summary>
        /// Gets/sets record id.
        /// </summary>
        public string Id
        {
            get { return DefaultEntity.Id; }
            set { DefaultEntity.Id = value; }
        }
        /// <summary>
        /// Indexer.  Gets/sets field value via reflection.
        /// </summary>
        /// <param name="fieldName">Name of the field whose value to get or set.</param>
        /// <returns>Field value.</returns>
        public string this[string fieldName]
        {
            get { return DefaultEntity[fieldName]; }
            set { DefaultEntity[fieldName] = value; }
        }
        /// <summary>
        /// Gets primary key field name.
        /// </summary>
        public string PrimaryKeyFieldName
        {
            get { return DefaultEntity.PrimaryKeyFieldName; }
        }
        /// <summary>
        /// Gets database table name from base implementation.
        /// </summary>
        public string DatabaseTableName
        {
            get { return DefaultEntity.DatabaseTableName; }
        }
        /// <summary>
        /// Gets provider from underlying records.
        /// </summary>
        public IQueryProvider Provider { get { return Queryable.Provider; } }
        /// <summary>
        /// Gets expression from underlying records.
        /// </summary>
        public Expression Expression { get { return Queryable.Expression; } }
        /// <summary>
        /// Gets enumerator from underlying records.
        /// </summary>
        /// <returns>A IEnumerator&lt;T&gt; that can be used to iterate through the collection.</returns>
        public IEnumerator GetEnumerator()
        {
            return List.GetEnumerator();
        }
        /// <summary>
        /// Locates a record for a given criteria expression.
        /// </summary>
        /// <param name="predicate">Search criteria expression.</param>
        /// <returns>Matched record when found, otherwise null.</returns>
        public T Find(Expression<Func<T, bool>> predicate)
        {
            return this.FirstOrDefault(predicate);
        }
        /// <summary>
        /// Creates instance with provided records.
        /// </summary>
        /// <param name="records">Records to hydrate instance with.</param>
        protected MockData(IList<T> records)
        {
            List = records;
            DefaultEntity = new DefaultEntity();
        }
        /// <summary>
        /// Gets/sets underlying records.
        /// </summary>
        private IList<T> List { get; set; }
        /// <summary>
        /// Gets typed queryable from underlying records.
        /// </summary>
        private IQueryable<T> Queryable { get { return List.AsQueryable(); } }
        /// <summary>
        /// Default entity.
        /// </summary>
        private IEntity DefaultEntity { get; set; }
    }
}